/******************************************************************************
 * 
 * Announce: CSharpKit, Basic algorithms, components and definitions.
 *           Copyright (C) ShenYongchen.
 *           All rights reserved.
 *   Author: 申永辰.郑州 (shenyczz@163.com)
 *  WebSite: http://github.com/shenyczz/CSharpKit
 *
 * THIS CODE IS LICENSED UNDER THE MIT LICENSE (MIT).
 * THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 
 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
 * IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
 * PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
 * 
******************************************************************************/

namespace CSharpKit.SVM
{
    /// <summary>
    /// SVR_Q
    /// </summary>
    internal class QM_SVR : Kernel
    {
        public QM_SVR(SvmProblem prob, SvmParameter param)
            : base(prob.Count, prob.X, param)
        {
            l = prob.Count;
            cache = new Cache(prob.Count, (long)(param.CacheSize * (1 << 20)));
            QD = new double[2 * l];
            sign = new sbyte[2 * l];
            index = new int[2 * l];
            for (int k = 0; k < l; k++)
            {
                sign[k] = 1;
                sign[k + l] = -1;
                index[k] = k;
                index[k + l] = k;
                QD[k] = KernelFunction(k, k);
                QD[k + l] = QD[k];
            }
            buffer = new float[][] { new float[2 * l], new float[2 * l] };
            next_buffer = 0;
        }

        private readonly int l;
        private readonly Cache cache;
        private readonly sbyte[] sign;
        private readonly int[] index;
        private int next_buffer;
        private float[][] buffer;
        private readonly double[] QD;

        public override float[] GetQ(int i, int len)
        {
            float[] data;
            int j, real_i = index[i];
            if (cache.GetData(real_i, out data, l) < l)
            {
                for (j = 0; j < l; j++)
                    data[j] = (float)KernelFunction(real_i, j);
            }

            // reorder and copy
            float[] buf = buffer[next_buffer];
            next_buffer = 1 - next_buffer;
            sbyte si = sign[i];
            for (j = 0; j < len; j++)
                buf[j] = (float)si * sign[j] * data[index[j]];
            return buf;
        }

        public override double[] GetQD()
        {
            return QD;
        }

        public override void SwapIndex(int i, int j)
        {
            do { sbyte _ = sign[i]; sign[i] = sign[j]; sign[j] = _; } while (false);
            do { int _ = index[i]; index[i] = index[j]; index[j] = _; } while (false);
            do { double _ = QD[i]; QD[i] = QD[j]; QD[j] = _; } while (false);
        }
        
        // void swap_index(int i, int j) const
        // {
        //     swap(sign[i], sign[j]);
        //     swap(index[i], index[j]);
        //     swap(QD[i], QD[j]);
        // }

        //}}@@@
    }


}
